package com.wxp.uniplugin_amap;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;

import com.alibaba.fastjson.JSONObject;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationClientOption.AMapLocationMode;
import com.amap.api.location.AMapLocationListener;
import com.taobao.weex.WXSDKEngine;
import com.taobao.weex.annotation.JSMethod;
import com.taobao.weex.bridge.JSCallback;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 扩展高德持续定位模块
 *
 * @author wxp
 * @date 2020-08-22
 */
public class AMapModule extends WXSDKEngine.DestroyableModule {

    // 通知管理器
    private NotificationManager notificationManager = null;
    // 通知 channel 名称
    private static final String NOTIFICATION_CHANNEL_NAME = "BackgroundLocation";
    // 是否创建通知频道
    private boolean isCreateChannel = false;
    // 权限请求 code
    private static final int PERMISSON_REQUESTCODE = 0;
    // 后台定位权限
    private final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
    // amap 客户端
    public AMapLocationClient aMapLocationClient = null;

    // 需要的权限列表
    private String[] needPermissions = {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.READ_PHONE_STATE
    };

    // 初始化 amap client
    private void initAmap() {
        aMapLocationClient = new AMapLocationClient(mWXSDKInstance.getContext());
    }

    // 获取默认 AMapLocationClientOption
    private AMapLocationClientOption getDefaultOption() {
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        mOption.setLocationMode(AMapLocationMode.Hight_Accuracy);//可选，设置定位模式，可选的模式有高精度、仅设备、仅网络。默认为高精度模式
        mOption.setGpsFirst(false);//可选，设置是否gps优先，只在高精度模式下有效。默认关闭
        mOption.setHttpTimeOut(30000);//可选，设置网络请求超时时间。默认为30秒。在仅设备模式下无效
        mOption.setInterval(2000);//可选，设置定位间隔。默认为2秒
        mOption.setNeedAddress(true);//可选，设置是否返回逆地理地址信息。默认是true
        mOption.setOnceLocation(false);//可选，设置是否单次定位。默认是false
        mOption.setOnceLocationLatest(false);//可选，设置是否等待wifi刷新，默认为false.如果设置为true,会自动变为单次定位，持续定位时不要使用
        AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选， 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
        mOption.setSensorEnable(false);//可选，设置是否使用传感器。默认是false
        mOption.setWifiScan(true); //可选，设置是否开启wifi扫描。默认为true，如果设置为false会同时停止主动刷新，停止以后完全依赖于系统刷新，定位位置可能存在误差
        mOption.setLocationCacheEnable(true); //可选，设置是否使用缓存定位，默认为true
        mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);//可选，设置逆地理信息的语言，默认值为默认语言（根据所在地区选择语言）
        return mOption;
    }

    /**
     * 开始持续定位
     * 前台请求格式
     * const wxp_AMap = uni.requireNativePlugin("WXP-AMap")
     * wxp_AMap.start({
     * 'setInterval': 5000, // 不是必须的
     * 'cacheEnable': true // 不是必须的
     * }, result => { // 结果回调
     * console.log(JSON.stringify(result))
     * })
     *
     * @param options
     * @param jsCallback
     */
    @JSMethod(uiThread = true)
    public void start(final JSONObject options, final JSCallback jsCallback) {
        initAmap();
        AMapLocationClientOption defaultOption = getDefaultOption();
        if (mWXSDKInstance.getContext() instanceof Activity) {
            long setInterval = options.containsKey("setInterval") ? options.getLongValue("setInterval") : 2000; // 设置过期时间
            boolean cacheEnable = !options.containsKey("cacheEnable") || options.getBooleanValue("cacheEnable");// 是否缓存

            defaultOption.setInterval(setInterval);
            defaultOption.setLocationCacheEnable(cacheEnable);
        }
        aMapLocationClient.setLocationOption(defaultOption);

        // 位置变化监听器
        AMapLocationListener aMapLocationListener = new AMapLocationListener() {
            // 位置变化回调
            @Override
            public void onLocationChanged(AMapLocation aMapLocation) {
                JSONObject jsonObject = new JSONObject();
                if (aMapLocation == null) return;
//                aMapLocation.setCoordType("GCJ02");
                if (aMapLocation.getErrorCode() == 0) {
//                    DPoint dPoint = getLatLng(aMapLocation.getLatitude(), aMapLocation.getLongitude());
                    jsonObject.put("code", aMapLocation.getErrorCode()); // 响应错误码
                    jsonObject.put("message", aMapLocation.getErrorInfo()); // 响应信息
//                    jsonObject.put("coordType", aMapLocation.getCoordType()); // 坐标系类型
                    jsonObject.put("type", aMapLocation.getLocationType()); // 定位来源
                    jsonObject.put("lng", aMapLocation.getLongitude()); // 经度
                    jsonObject.put("lat", aMapLocation.getLatitude()); // 纬度
                    jsonObject.put("speed", aMapLocation.getSpeed()); // 速度
                    jsonObject.put("country", aMapLocation.getCountry()); // 国家
                    jsonObject.put("province", aMapLocation.getProvince()); // 省份
                    jsonObject.put("city", aMapLocation.getCity()); // 城市
                    jsonObject.put("district", aMapLocation.getDistrict()); // 县区
                    jsonObject.put("street", aMapLocation.getStreet()); // 街道
                    jsonObject.put("address", aMapLocation.getAddress()); // 地址
                } else {
                    jsonObject.put("code", aMapLocation.getErrorCode()); // 响应错误码
                    jsonObject.put("message", aMapLocation.getErrorInfo()); // 响应信息
                }
                // 前台结果回调
                jsCallback.invokeAndKeepAlive(jsonObject);
            }
        };
        aMapLocationClient.setLocationListener(aMapLocationListener); // 设置默认监听器
        aMapLocationClient.enableBackgroundLocation(2001, notification()); // 是否开启后台定位，需要权限 android.permission.ACCESS_BACKGROUND_LOCATION
        aMapLocationClient.startLocation(); // 开始定位
    }

    /**
     * 停止定位
     *
     * @param jsCallback js回调
     */
    @JSMethod(uiThread = false)
    public void stop(JSCallback jsCallback) {
        JSONObject jsonObject = new JSONObject();
        aMapLocationClient.stopLocation();
        if (jsCallback != null) {
            jsonObject.put("code", 0);
            jsonObject.put("message", "已停止定位");
            jsCallback.invoke(jsonObject);
        }
    }

    /**
     * 销毁定位
     *
     * @param jsCallback js回调
     */
    @JSMethod(uiThread = false)
    public void destroy(JSCallback jsCallback) {
        aMapLocationClient.onDestroy();
        aMapLocationClient = null;
    }

    @Override
    public void onActivityCreate() {
        super.onActivityCreate();
        if (Build.VERSION.SDK_INT > 28 && mWXSDKInstance.getContext().getApplicationInfo().targetSdkVersion > 28) {
            this.needPermissions = new String[]{
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.READ_PHONE_STATE,
                    ACCESS_BACKGROUND_LOCATION
            };
        }
    }

    private boolean isNeedCheck = true;

    @Override
    public void onActivityResume() {
        super.onActivityResume();
    }

    @Override
    public void onActivityDestroy() {
        if (null != aMapLocationClient) {
            aMapLocationClient.onDestroy();
            aMapLocationClient = null;
        }
    }

    /**
     * 构建通知
     *
     * @return Notification
     */
    @SuppressLint("NewApi")
    private Notification notification() {
        Notification.Builder builder = null;
        Notification notification = null;
        if (Build.VERSION.SDK_INT >= 26) {
            if (notificationManager == null) {
                mWXSDKInstance.getContext();
                notificationManager = (NotificationManager) mWXSDKInstance.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
            }

            String channelId = mWXSDKInstance.getContext().getPackageName();
            if (!isCreateChannel) {
                NotificationChannel notificationChannel = new NotificationChannel(channelId, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
                notificationChannel.enableLights(true);
                notificationChannel.setLightColor(Color.BLUE);
                notificationChannel.setShowBadge(true);
                notificationManager.createNotificationChannel(notificationChannel);
                isCreateChannel = true;
            }
            builder = new Notification.Builder(getContext(), channelId);
        } else {
            builder = new Notification.Builder(getContext());
        }
//        PackageManager.
        builder.setContentTitle(getAppName(getContext()))
                .setContentText("正在运行")
                .setWhen(System.currentTimeMillis());
        if (Build.VERSION.SDK_INT >= 16) {
            notification = builder.build();
        } else {
            return builder.getNotification();
        }
        return notification;
    }

    /**
     * 获取 Context
     *
     * @return Context
     */
    private Context getContext() {
        return mWXSDKInstance.getContext();
    }

    private ApplicationInfo getApplicationInfo() {
        return mWXSDKInstance.getContext().getApplicationInfo();
    }

    // 权限请求
    @JSMethod(uiThread = true)
    public void permission(JSCallback jsCallback) {
        if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
            if (isNeedCheck) {
                checkPermissions(needPermissions);
            }
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msg", "我要授权了呢！");
        jsCallback.invoke(jsonObject);
    }

    /**
     * 检查权限
     *
     * @param permissions String[]
     */
    private void checkPermissions(String[] permissions) {
        if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
            List<String> needRequestPermissionList = findDeniedPermissions(permissions);
            if (needRequestPermissionList != null && needRequestPermissionList.size() > 0) {
                String[] array = needRequestPermissionList.toArray(new String[needRequestPermissionList.size()]);
                ActivityCompat.requestPermissions((Activity) this.getContext(), array, 1);
            }
        }
    }

    private boolean needCheckBackLocation = false;

    private List<String> findDeniedPermissions(String[] permissions) {
        List<String> needRequestPermissionsList = new ArrayList<>();
        if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
            for (String permission : permissions) {
                try {
                    Integer checkSelfPermission = this.getContext().checkSelfPermission(permission);
                    Method shouldShowRequestPermissionRationale = this.getContext().getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
//                    Method shouldShowRequestPermissionRationale = getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
                    if (checkSelfPermission != PackageManager.PERMISSION_GRANTED || (Boolean) shouldShowRequestPermissionRationale.invoke(this.getContext(), permission)) {
                        if (!needCheckBackLocation && ACCESS_BACKGROUND_LOCATION.equals(permission)) {
                            continue;
                        }
                        needRequestPermissionsList.add(permission);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return needRequestPermissionsList;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == PERMISSON_REQUESTCODE) {
            if (!verifyPermissions(grantResults)) {
                showMissingPermissionDialog();
                isNeedCheck = false;
            }
        }
    }

    private void showMissingPermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setTitle("提示");
        builder.setMessage("当前应用缺少必要权限。\n\n请点击\"设置\"-\"权限\"-打开所需权限。");

        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });
        builder.setPositiveButton("设置", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                AMapModule.this.startAppSettings();
            }
        });
        builder.setCancelable(false);
        builder.show();
    }

    private boolean verifyPermissions(int[] grantResults) {
        for (int grantResult : grantResults) {
            if (grantResult != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void destroy() {
        aMapLocationClient.onDestroy();
        aMapLocationClient = null;
    }

    private void startAppSettings() {
        Intent intent = new Intent(
                Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + getContext().getPackageName()));
        getContext().startActivity(intent);
    }

    // 获取应用名称
    private String getAppName(Context context) {
        String appName = "";
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            int labelRes = packageInfo.applicationInfo.labelRes;
            appName = context.getResources().getString(labelRes);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return appName;
    }
}
